package com.sansecy.android.simplevideo;

import android.content.Context;
import android.graphics.Color;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;

import java.io.IOException;

/**
 * A SurfaceView-based video player implementing the Player interface
 */
public class SimpleSurfaceVideoView extends FrameLayout implements Player {
    private static final String TAG = "SimpleSurfaceVideoView";
    // All the player states from SimpleVideoView
    private static final int STATE_IDLE = 0;
    private static final int STATE_PREPARING = 1;
    private static final int STATE_PREPARED = 2;
    private static final int STATE_PLAYING = 3;
    private static final int STATE_PAUSED = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;
    private static final int STATE_ERROR = 6;

    private String mUrl;
    private Uri mUri;
    private VideoSurfaceView mVideoSurfaceView;
    private MediaPlayer mMediaPlayer;
    private int mCurrentState = STATE_IDLE;
    private int mTargetState = STATE_IDLE;
    private boolean mLooping = false;
    private int mBufferingPercent;
    private SurfaceHolder mSurfaceHolder;
    private boolean mIsReleaseOnDetached = true;

    // Listeners
    private OnPreparedListener mOnPreparedListener;
    private OnCompletionListener mOnCompletionListener;
    private OnBufferingUpdateListener mOnBufferingUpdateListener;
    private OnSeekCompleteListener mOnSeekCompleteListener;
    private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
    private OnErrorListener mOnErrorListener;
    private OnInfoListener mOnInfoListener;
    private boolean surfaceCreated;
    private VideoTextureView textureView;
    private SurfaceTexture surface;

    public SimpleSurfaceVideoView(Context context) {
        super(context);
        init();
    }

    public SimpleSurfaceVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SimpleSurfaceVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    int fps;
    private long currentedTimeMillis;
    private TextView textView;

    boolean useSurfaceView = false;
    private void init() {
        setBackgroundColor(Color.BLACK);
        if (useSurfaceView) {
            addSurfaeView();
        } else {
            addTextureView();
        }
        textView = new TextView(getContext());
        textView.setBackgroundColor(Color.WHITE);
        textView.setTextSize(16);
        LayoutParams params1 = new LayoutParams(-2, -2);
        params1.gravity = Gravity.TOP | Gravity.CENTER;
        textView.setTextColor(Color.RED);
        addView(textView, params1);
    }

    private void addSurfaeView() {
        mVideoSurfaceView = new VideoSurfaceView(getContext());
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        params.gravity = Gravity.CENTER;
        // Get surface holder and add callback
        addView(mVideoSurfaceView, params);
        mSurfaceHolder = mVideoSurfaceView.getHolder();
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                Log.d(TAG, "surfaceCreated() called with: holder = [" + holder + "]");
                // If we're in the middle of preparing, set the surface holder now
                mSurfaceHolder = holder;
                surfaceCreated = true;
                // If we're in the middle of preparing, set the surface holder now
                if (mMediaPlayer != null) {
                    Log.d(TAG, "surfaceCreated() called with: mMediaPlayer.setDisplay");
                    mMediaPlayer.setDisplay(mSurfaceHolder);
                    if (mMediaPlayer.isPlaying()) {
                        int videoWidth = mMediaPlayer.getVideoWidth();
                        int videoHeight = mMediaPlayer.getVideoHeight();
                        mVideoSurfaceView.setVideoWidthHeight(videoWidth, videoHeight);
                    }
                }
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
                Log.d(TAG, "surfaceChanged() called with: holder = [" + holder + "], format = [" + format + "], width = [" + width + "], height = [" + height + "]");
                mSurfaceHolder = holder;
                surfaceCreated = false;
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                mSurfaceHolder = null;
                surfaceCreated = false;
            }
        });
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    private void addTextureView() {
        textureView = new VideoTextureView(getContext());
        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                Log.d(TAG, "onSurfaceTextureAvailable() called with: surface = [" + surface + "], width = [" + width + "], height = [" + height + "]");
                SimpleSurfaceVideoView.this.surface = surface;
                if (mMediaPlayer != null) {
                    Log.d(TAG, "onSurfaceTextureAvailable() called with: mMediaPlayer.setSurface");
                    mMediaPlayer.setSurface(new Surface(surface));
                    if (mMediaPlayer.isPlaying()) {
                        int videoWidth = mMediaPlayer.getVideoWidth();
                        int videoHeight = mMediaPlayer.getVideoHeight();
                        textureView.setVideoWidthHeight(videoWidth, videoHeight);
                    }
                }
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
                boolean rest = false;
                if (System.currentTimeMillis() - currentedTimeMillis > 1000) {
                    textView.setText(String.valueOf(fps));
                    fps = 0;
                    currentedTimeMillis = System.currentTimeMillis();
                    rest = true;
                }
                if (!rest) {
                    fps++;
                }
            }
        });
        LayoutParams params = new LayoutParams(-1, -1);
        params.gravity = Gravity.CENTER;
        addView(textureView, params);
    }

    public void switchSurface() {
        if (useSurfaceView) {
            useSurfaceView = false;
            removeView(mVideoSurfaceView);
            addTextureView();
        } else {
            useSurfaceView = true;
            removeView(textureView);
            addSurfaeView();
        }
    }

    @Override
    public void loadUrl(String url) {
        mUrl = url;
        mUri = null;
    }

    @Override
    public void loadUri(Uri uri) {
        mUri = uri;
        mUrl = null;
    }

    @Override
    public void openVideo() {
        try {
            mMediaPlayer = new MediaPlayer();
            if (mUrl != null) {
                mMediaPlayer.setDataSource(mUrl);
            } else {
                mMediaPlayer.setDataSource(getContext(), mUri);
            }
            mMediaPlayer.setScreenOnWhilePlaying(true);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setLooping(mLooping);
            Log.d(TAG, "openVideo() called mLooping:" + mLooping);
            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnInfoListener(mInfoListener);
            mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);

            // Set the surface holder instead of SurfaceTexture - only if surface exists
            if (useSurfaceView && surfaceCreated) {
                Log.d(TAG, "mMediaPlayer.setDisplay");
                mMediaPlayer.setDisplay(mSurfaceHolder);
            } else {
                if (SimpleSurfaceVideoView.this.surface != null) {
                    Log.d(TAG, "mMediaPlayer.setSurface");
                    mMediaPlayer.setSurface(new Surface(SimpleSurfaceVideoView.this.surface));
                }
            }
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mMediaPlayer.prepareAsync();
            mCurrentState = STATE_PREPARING;
            Log.d(TAG, "openVideo: 正在准备");
        } catch (IOException | IllegalArgumentException | SecurityException | IllegalStateException e) {
            e.printStackTrace();
            Log.d(TAG, "openVideo: 准备出错");
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            if (mErrorListener != null) {
                mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            }
        }
    }

    public void setLooping(boolean looping) {
        mLooping = looping;
        if (mMediaPlayer != null) {
            mMediaPlayer.setLooping(looping);
        }
    }

    @Override
    public void start() {
        if (isInPlaybackState()) {
            if (mMediaPlayer != null) {
                mMediaPlayer.start();
                Log.d(TAG, "start: 正在播放");
                mCurrentState = STATE_PLAYING;
            }
        }
        mTargetState = STATE_PLAYING;
    }

    @Override
    public void pause() {
        if (isInPlaybackState()) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                Log.d(TAG, "pause: 已暂停");
                mCurrentState = STATE_PAUSED;
            }
        }
        mTargetState = STATE_PAUSED;
    }

    public boolean isInPlaybackState() {
//        Log.d(TAG, "isInPlaybackState: 当前状态 = " + mCurrentState);
        return (mMediaPlayer != null &&
                mCurrentState != STATE_ERROR &&
                mCurrentState != STATE_IDLE &&
                mCurrentState != STATE_PREPARING);
    }

    @Override
    public int getDuration() {
        if (!isInPlaybackState()) {
            return 0;
        }
        if (mMediaPlayer != null) {
            return mMediaPlayer.getDuration();
        }
        return 0;
    }

    @Override
    public int getCurrentPosition() {
        if (!isInPlaybackState()) {
            return 0;
        }
        if (mMediaPlayer != null) {
            return mMediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    @Override
    public void seekTo(int pos) {
        if (mMediaPlayer != null) {
            mMediaPlayer.seekTo(pos);
        }
    }

    @Override
    public boolean isPlaying() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.isPlaying();
        }
        return false;
    }

    @Override
    public int getBufferPercentage() {
        return mBufferingPercent;
    }

    @Override
    public void stopPlayback() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            Log.d(TAG, "stopPlayback: 已停止播放");
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
        }
    }


    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            Log.d(TAG, "onBufferingUpdate() called with: mp = [" + mp + "], percent = [" + percent + "]");
            mBufferingPercent = percent;
            if (mOnBufferingUpdateListener != null) {
                mOnBufferingUpdateListener.onBufferingUpdate(percent);
            }
        }
    };

    private MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            Log.d(TAG, "onPrepared() called with: mp = [" + mp + "]");
            mCurrentState = STATE_PREPARED;
            if (mOnPreparedListener != null) {
                mOnPreparedListener.onPrepared();
            }
            Log.d(this.getClass().getSimpleName() + "-App", ":onPrepared mTargetState == STATE_PLAYING" + mTargetState);
            if (mTargetState == STATE_PLAYING) {
                start();
            }
        }
    };

    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
            if (mOnVideoSizeChangedListener != null) {
                mOnVideoSizeChangedListener.onVideoSizeChanged(width, height);
            }
            Log.d(TAG, "onVideoSizeChanged() called with: mp = [" + mp + "], width = [" + width + "], height = [" + height + "]");
            if (mVideoSurfaceView != null) {
                mVideoSurfaceView.setVideoWidthHeight(width, height);
            }
            if (textureView != null) {
                textureView.setVideoWidthHeight(width, height);
            }
        }
    };

    MediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(MediaPlayer mp) {
            Log.d(TAG, "onSeekComplete() called with: mp = [" + mp + "]");
            if (mOnSeekCompleteListener != null) {
                mOnSeekCompleteListener.onSeekComplete();
            }
        }
    };

    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
        public void onCompletion(MediaPlayer mp) {
            Log.d(TAG, "onCompletion() called with: mp = [" + mp + "]");
            mCurrentState = STATE_PLAYBACK_COMPLETED;
            mTargetState = STATE_PLAYBACK_COMPLETED;
            if (mOnCompletionListener != null) {
                mOnCompletionListener.onCompletion();
            }
        }
    };

    private MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
        public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            Log.d(TAG, "onError() called with: mp = [" + mp + "], framework_err = [" + framework_err + "], impl_err = [" + impl_err + "]");
            if (mOnErrorListener != null) {
                return mOnErrorListener.onError(framework_err, impl_err);
            }
            return true;
        }
    };

    private MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            return mOnInfoListener != null && mOnInfoListener.onInfo(what, extra);
        }
    };

    // Setters for Player interface listeners
    public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
        mOnPreparedListener = onPreparedListener;
    }

    public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener onVideoSizeChangedListener) {
        mOnVideoSizeChangedListener = onVideoSizeChangedListener;
    }

    public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
        mOnCompletionListener = onCompletionListener;
    }

    public void setOnErrorListener(OnErrorListener onErrorListener) {
        mOnErrorListener = onErrorListener;
    }

    public void setOnInfoListener(OnInfoListener onInfoListener) {
        mOnInfoListener = onInfoListener;
    }

    public void setOnBufferingUpdateListener(OnBufferingUpdateListener onBufferingUpdateListener) {
        mOnBufferingUpdateListener = onBufferingUpdateListener;
    }

    public void setOnSeekCompleteListener(OnSeekCompleteListener onSeekCompleteListener) {
        mOnSeekCompleteListener = onSeekCompleteListener;
    }

    // Convert Player interface listeners to MediaPlayer listeners internally
    private void convertListeners() {
        mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
        mMediaPlayer.setOnPreparedListener(mPreparedListener);
        mMediaPlayer.setOnCompletionListener(mCompletionListener);
        mMediaPlayer.setOnErrorListener(mErrorListener);
        mMediaPlayer.setOnInfoListener(mInfoListener);
        mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
        mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
    }

    // Added setReleaseWhenDetached method
    public void setReleaseWhenDetached(boolean releaseOnDetached) {
        mIsReleaseOnDetached = releaseOnDetached;
    }

    // Added release method
    public void release() {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
            Log.d(TAG, "release: 释放资源");
        }
    }

    // Added onDetachedFromWindow override
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mIsReleaseOnDetached) {
            pause();
            release();
        }
    }
}